// JED Manager
// (c) jimon game studio

#include "CJEDManager.h"
#include <stdlib.h>

namespace je
{
	namespace core
	{
		IMPLEMENT_SINGLETON(JEDManager,JE_ENGINE_FUNCTION_CALL)

		//! Constructor
		CJEDManager::CJEDManager()
		{
			SetJEDManager(this);

			JENEW(Factory,jeJED_DataBlock::DataBlockFactoryType)

			Factory->Register<jeJED_NullBlock>(JEDDBT_NULL);
			Factory->Register<jeJED_OffsetTableBlock>(JEDDBT_OFFSET_TABLE);
			Factory->Register<jeJED_MeshBlock>(JEDDBT_MESH);
			Factory->Register<jeJED_SurfaceBlock>(JEDDBT_SURFACE);
			Factory->Register<jeJED_BitmapFontBlock>(JEDDBT_BITMAPFONT);
		}

		//! Destructor
		CJEDManager::~CJEDManager()
		{
			JEDELETE(Factory)
			SetJEDManager(NULL);
		}

		//! Get Factory
		jeJED_DataBlock::DataBlockFactoryType * CJEDManager::GetFactory()
		{
			return Factory;
		}

		//! Load
		jeJED_DataBlock * CJEDManager::Load(IBuffer * Buffer,const jeStringw & Path)
		{
			Buffer->Lock(BLT_READ);
			Buffer->SetStreamWorkMode(true);
			Buffer->SetPosition(0);

			c8 Format_Identificator_1[5] = "jemf";

			c8 Current_Format_Identificator_1[5];
			memset(Current_Format_Identificator_1,0,5);

			Buffer->Read(Current_Format_Identificator_1,4);
			
			if(memcmp(Format_Identificator_1,Current_Format_Identificator_1,5))
			{
				Buffer->UnLock();
				return NULL;
			}

			u8 Identificator_2_Byte1 = 0,Identificator_2_Byte2 = 0,Identificator_2_Byte3 = 0;
			
			Buffer->Read(&Identificator_2_Byte1,1);
			Buffer->Read(&Identificator_2_Byte2,1);
			Buffer->Read(&Identificator_2_Byte3,1);

			if(Identificator_2_Byte2 != (Identificator_2_Byte1+Identificator_2_Byte3))
			{
				Buffer->UnLock();
				return NULL;
			}

			u8 Version = 0;
			Buffer->Read(&Version,1);

			if(Version != 1)
			{
				Buffer->UnLock();
				return NULL;
			}

			u8 FormatFlags = 0;
			Buffer->Read(&FormatFlags,1);

			if(FormatFlags != 0)
			{
				Buffer->UnLock();
				return NULL;
			}

			u32 Reserved1 = 0,Reserved2 = 0;
			f32 Reserved3 = 0.0f;
			Buffer->Read(&Reserved1,4);
			Buffer->Read(&Reserved2,4);
			Buffer->Read(&Reserved3,4);

			u16 OffsetBlockId = 0;
			Buffer->Read(&OffsetBlockId,2);

			jeJED_OffsetTableBlock * OffsetBlock = static_cast<jeJED_OffsetTableBlock*>(CreateDataBlock(OffsetBlockId));
			OffsetBlock->Load(Buffer);

			jeJED_DataBlock * Root = NULL;

			if(Path.GetSize() > 0)
			{
				u32 Offset = OffsetBlock->GetOffset(Path);
				Buffer->SetPosition(Offset);

				u16 BlockId;
				Buffer->Read(&BlockId,2);

				Root = CreateDataBlock(BlockId);
				Root->Load(Buffer);

				Buffer->SetPosition(Buffer->GetSize()-5);
			}
			else
			{
				u16 BlockId;
				Buffer->Read(&BlockId,2);

				Root = CreateDataBlock(BlockId);
				Root->Load(Buffer);
			}

			OffsetBlock->Drop();

			c8 End_Identificator[6] = "jemfe";

			c8 Current_End_Identificator[6];
			memset(Current_End_Identificator,0,6);

			Buffer->Read(Current_End_Identificator,5);

			if(memcmp(End_Identificator,Current_End_Identificator,6))
			{
				Root->Drop();
				Buffer->UnLock();
				return NULL;
			}

			Buffer->UnLock();

			return Root;
		}

		//! Save
		void CJEDManager::Save(IBuffer * Buffer,jeJED_DataBlock * RootBlock)
		{
			RootBlock->PrepareForSave();

			u32 HeaderSize = 4 + 3 + 1 + 1 + 4 + 4 + 4;

			jeJED_OffsetTableBlock * Offset = static_cast<jeJED_OffsetTableBlock*>(CreateDataBlock(1));
			Offset->CalculateOffsets(RootBlock,HeaderSize);

			u32 GlobalSize = HeaderSize + Offset->GetBlockSize() + RootBlock->GetBlockSize() + 5;

			Buffer->Lock(BLT_WRITE);
			Buffer->SetStreamWorkMode(true);
			Buffer->Allocate(GlobalSize);
			Buffer->SetPosition(0);

			c8 Format_Identificator_1[5] = "jemf";
			Buffer->Write(Format_Identificator_1,4);

			u8 Identificator_2_Byte1 = rand()%127,Identificator_2_Byte3 = rand()%127,Identificator_2_Byte2 = Identificator_2_Byte1 + Identificator_2_Byte3;
			Buffer->Write(&Identificator_2_Byte1,1);
			Buffer->Write(&Identificator_2_Byte2,1);
			Buffer->Write(&Identificator_2_Byte3,1);

			u8 Version = 1;
			Buffer->Write(&Version,1);

			u8 FormatFlags = 0;
			Buffer->Write(&FormatFlags,1);

			u32 Reserved1 = 0,Reserved2 = 0;
			f32 Reserved3 = 0.0f;
			Buffer->Write(&Reserved1,4);
			Buffer->Write(&Reserved2,4);
			Buffer->Write(&Reserved3,4);

			Offset->Save(Buffer);
			
			RootBlock->Save(Buffer);

			c8 End_Identificator[6] = "jemfe";
			Buffer->Write(End_Identificator,5);

			Buffer->UnLock();

			Offset->Drop();
		}

		//! Return true if this is jed format
		u1 CJEDManager::IsCanLoadThis(IBuffer * Buffer)
		{
			Buffer->Lock(BLT_READ);
			Buffer->SetStreamWorkMode(true);
			Buffer->SetPosition(0);

			c8 Format_Identificator_1[5] = "jemf";

			c8 Current_Format_Identificator_1[5];
			memset(Current_Format_Identificator_1,0,5);

			Buffer->Read(Current_Format_Identificator_1,4);
			
			if(memcmp(Format_Identificator_1,Current_Format_Identificator_1,5))
			{
				Buffer->UnLock();
				return false;
			}

			u8 Identificator_2_Byte1,Identificator_2_Byte2,Identificator_2_Byte3;
			
			Buffer->Read(&Identificator_2_Byte1,1);
			Buffer->Read(&Identificator_2_Byte2,1);
			Buffer->Read(&Identificator_2_Byte3,1);

			if(Identificator_2_Byte2 != (Identificator_2_Byte1+Identificator_2_Byte3))
			{
				Buffer->UnLock();
				return false;
			}

			u8 Version = 0;
			Buffer->Read(&Version,1);

			if(Version != 1)
			{
				Buffer->UnLock();
				return false;
			}

			u8 FormatFlags = 0;
			Buffer->Read(&FormatFlags,1);

			if(FormatFlags != 0)
			{
				Buffer->UnLock();
				return false;
			}

			Buffer->UnLock();
			return true;
		}

	}
}
